package wangwenjun.phase1.reference.strong;

import wangwenjun.phase1.reference.CacheLoader;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

/**
 * @author ChangLiang
 * @date 2020/6/16
 */
public class LRUCache<K, V> {

    /**
     * 用于记录key值的顺序
     */
    private final LinkedList<K> keyList = new LinkedList<>();

    /**
     * 用于存放数据 这里使用的是Strong Reference
     */
    private final Map<K, V> cacheMap = new HashMap<>();

    /**
     * cache的最大容量
     */
    private final int capacity;

    /**
     * cacheLoader 接口提供了一种加载数据的方式
     */
    private final CacheLoader<K,V> cacheLoader;

    public LRUCache(int capacity, CacheLoader<K, V> cacheLoader) {
        this.capacity = capacity;
        this.cacheLoader = cacheLoader;
    }

    /**
     * put 方法可将Value 缓存至Cache 中，如果当前Cache 的容量超过了指定容量的大
     * 小， 则会将最先保存至Cache 中的数据丢弃掉
     * @param key
     * @param value
     */
    public void put(K key, V value) {

        // 当元素数量超过容量时， 将最老的数据清除
        if (keyList.size() >= capacity) {
            K oldestKey = keyList.removeFirst();
            cacheMap.remove(oldestKey);
        }
        // 如果数据已经存在，则从key的队列中删除
        if (keyList.contains(key)) {
            keyList.remove(key);
        }
        // 将key 存放至队尾
        keyList.addLast(key);
        cacheMap.put(key, value);
    }

    /**
     * get 方法根据key 从Cache中获取数据，如果数据存在则先从keyList 中删除，然后
     * 再插入到队尾，否则调用CacheLoader 的load 方法进行加载
     * @param key
     * @return
     */
    public V get(K key) {
        V value;
        // 先将key 从key list 中删除
        boolean isSuccess = keyList.remove(key);
        // 如果删除失败则表明该数据不存在
        if (!isSuccess) {
            // 通过cache loader 对数据进行加载
            value = cacheLoader.load(key);
            this.put(key, value);
        } else {
            // 如果删除成功，则从cache 中返回数据，并且将key 再次放到队尾
            value = cacheMap.get(key);
            keyList.addLast(key);
        }
        return value;
    }

    @Override
    public String toString() {
        return this.keyList.toString();
    }
}
